package com.bfmet.crawler;

import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.Div;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;

import com.bfmet.common.DAOService;
import com.bfmet.common.base.EntityBase;
import com.bfmet.entity.Metal;
import com.bfmet.entity.News;

public class MetalSpider extends Spider {

	@Override
	public void run() {
		for (Metal.Type metal : Metal.Type.values()) {
			this.begin("http://www.cnmn.com.cn/" + metal.name() + ".html",
					metal);
		}
	}

	protected void begin(String url, Metal.Type type) {
		try {
			Parser p = new Parser(url);
			p.setEncoding("utf-8");
			NodeList divList = p.parse(new AndFilter(new TagNameFilter("div"),
					new HasAttributeFilter("class", "clo400")));
			Node ul = divList.elementAt(0).getChildren().elementAt(1);
			for (Node node : ul.getChildren().toNodeArray()) {
				if (node.getFirstChild() instanceof LinkTag) {
					LinkTag a = (LinkTag) node.getFirstChild();
					String prefixUrl = url.substring(0,
							url.lastIndexOf("/") + 1);
					this.spideTwoLevelPage(prefixUrl + a.getLink(), type);
				}
			}
		} catch (Exception ex) {
			this.logException(ex);
		}
	}

	public void spideTwoLevelPage(String url, Metal.Type type) {
		try {
			log("Fetch two level begin..." + url);
			News news = new News();
			NodeFilter divf = new TagNameFilter("div");
			NodeFilter newsContent = new HasAttributeFilter("id", "newsContent");

			Parser p = new Parser(url);
			NodeList nodeList = p.parse(new AndFilter(divf, newsContent));
			if (nodeList.elementAt(0) instanceof Div) {
				Div div = (Div) nodeList.elementAt(0);
				String title = div.getFirstChild().getNextSibling()
						.toPlainTextString();
				this.log("title:" + title);
				news.setName(title);
				p.setInputHTML(div.toHtml());
				NodeList nl = p.parse(new AndFilter(divf,
						new HasAttributeFilter("id", "content")));
				if (nl.elementAt(0) instanceof Div) {
					Div divContent = (Div) nl.elementAt(0);
					String content = divContent.toPlainTextString();
					this.log("content:" + content);
					news.setContent(content);
				}
			}

			if (this.exist(news)) {
				News persistent = this.get(news);
				persistent.setTags(type.name());
				persistent.setModifyTime(new Date());
				DAOService.merge(persistent);
			} else {
				news.setTags(type.name());
				this.save(news);
			}
		} catch (Exception ex) {
			this.logException(ex);
		}
		log("Fetch two level end..." + url);
	}

	@SuppressWarnings("unchecked")
	protected <T extends EntityBase> T get(EntityBase entity) {
		EntityManager em = DAOService.getEM();
		try {
			Metamodel metamodel = em.getEntityManagerFactory().getMetamodel();
			EntityType<?> pClass = metamodel.entity(entity.getClass());

			Query query = em.createQuery("select n from " + pClass.getName()
					+ " n where n.name=:name");
			query.setParameter("name", entity.getName());
			return (T) query.getSingleResult();
		} finally {
			em.close();
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		MetalSpider ms = new MetalSpider();
		ms.run();
	}

}
